#pragma once
#include <tuple>

// tuple 元组 (类似与结构体，可存放多个任意个不同类型的元素)
namespace Anger
{
	// Index Tuple
	//参数索引 tuple
	template <unsigned... Indices>
	struct index_tuple
	{
		template <unsigned N>
		using append = index_tuple<Indices..., N>;
	};
     //n个参数
	template <unsigned Size>
	struct make_index_tuple
	{
		using type = typename make_index_tuple<Size - 1>::type::template append<Size - 1>;
	};
	//单个参数
	template <>
	struct make_index_tuple<0>
	{
		using type = index_tuple<>;
	};

	//参数转换为 tuple
	template<typename... Types>
	using to_index_tuple = typename make_index_tuple<sizeof...(Types)>::type;

	//函数参数映射调用
	template <typename Function, typename Tuple, unsigned... I>
	auto apply_impl(Function func, Tuple&& tuple, index_tuple<I...>)
	{
		return func(std::get<I>(tuple)...);
	}
	//lambad /function
	template <typename Function, typename... Args>
	auto apply(Function func, std::tuple<Args...> args, typename std::enable_if<!std::is_member_function_pointer<Function>::value>::type* = 0)
	{
		using indices = to_index_tuple<Args...>;
		return apply_impl(func, args, indices());
	}

	// Apply (Member functions)
	template <typename Class, typename Function, typename Tuple, unsigned... I>
	auto apply_impl(Class* inst, Function func, Tuple&& tuple, index_tuple<I...>)
	{
		return (inst->*func)(std::get<I>(tuple)...);
	}
	//class member function
	template <typename Class, typename Function, typename... Args>
	auto apply(Class* inst, Function func, std::tuple<Args...> args)
	{
		using indices = to_index_tuple<Args...>;
		return apply_impl(inst, func, args, indices());
	}
}
